#include "score_widget.h"

#include <QDir>
#include <QLabel>
#include <QList>
#include <QProcess>
#include <QPushButton>
#include <QScrollArea>
#include <QScrollBar>
#include <QVBoxLayout>

ScoreWidget::ScoreWidget(QWidget *parent):
  QWidget(parent) {
  scrollArea = new QScrollArea(this);
  scrollArea->setPalette(QPalette(Qt::white));
  scrollArea->setAutoFillBackground(true);

  imageLabel = new QLabel(scrollArea);
  scrollArea->setAlignment(Qt::AlignHCenter);
  scrollArea->setWidget(imageLabel);

  QVBoxLayout *vlayout = new QVBoxLayout;
  vlayout->addWidget(scrollArea);

  pageCountLabel = new QLabel(this);
  pageCountLabel->setToolTip("Numéro de page / nombre de page");

  prevButton = new QPushButton("<<", this);
  prevButton->setToolTip("Page précédente");
  connect(prevButton, SIGNAL(clicked()), this, SLOT(prevPage()));

  nextButton = new QPushButton(">>", this);
  nextButton->setToolTip("Page suivante");
  connect(nextButton, SIGNAL(clicked()), this, SLOT(nextPage()));

  initialize();

  QHBoxLayout *hlayout = new QHBoxLayout;
  hlayout->addStretch(0);
  hlayout->addWidget(prevButton);
  hlayout->addWidget(pageCountLabel);
  hlayout->addWidget(nextButton);
  hlayout->addStretch(0);

  vlayout->addLayout(hlayout);

  setLayout(vlayout);
}

/*!
 * Initialise les boutons et autres widgets
 */
void ScoreWidget::initialize() {
  pageCountLabel->setText("# / #");
  prevButton->setDisabled(true);
  nextButton->setDisabled(true);
  imageLabel->clear();
  imageLabel->adjustSize();
}

/*!
 * Génére les PNG de la partition en utilisant Lilypond
 */
void ScoreWidget::displayScore() {
  lilypond = new QProcess;
  connect(lilypond, SIGNAL(finished(int, QProcess::ExitStatus)),
          this, SLOT(trimImages()));
  lilypond->start("lilypond --png --output=tmp tmp-internal.ly");
}

/*!
 * Supprime les marges inutiles des fichiers PNG générés
 */
void ScoreWidget::trimImages() {
  delete lilypond;

  mogrify = new QList<QProcess*>;

  if(QFile::exists("tmp.png")) {
    pageCount = 1;

    mogrify->append(new QProcess);
    connect(mogrify->last(), SIGNAL(finished(int, QProcess::ExitStatus)),
            this, SLOT(displayFirstPage()));
    mogrify->last()->
      start("mogrify -trim -border 5 -bordercolor white tmp.png");
  }
  else {
    QStringList pngList =
        QDir::current().entryList(QStringList("tmp-page*.png"));
    pageCount = pngList.size();

    foreach(QString filename, pngList) {
      mogrify->append(new QProcess);
      connect(mogrify->last(), SIGNAL(finished(int, QProcess::ExitStatus)),
            this, SLOT(displayFirstPage()));
      mogrify->last()->start("mogrify -trim -border 5 -bordercolor white " +
                             filename);
    }
  }
}

/*!
 * Affiche la première page de la partition
 */
void ScoreWidget::displayFirstPage() {
  // tant qu'il y a un processus mogrify qui tourne
  foreach(QProcess *process, *mogrify)
    if(process->state() == QProcess::Starting ||
       process->state() == QProcess::Running)
      return;

  // quand ils ont tous terminé
  foreach(QProcess* process, *mogrify)
    delete process;
  delete mogrify;

  displayPage(1);
  emit firstPageDisplayed();
}

/*!
 * Affiche la page précédente
 */
void ScoreWidget::prevPage() {
  displayPage(currentPage-1);
}

/*!
 * Affiche la page suivante
 */
void ScoreWidget::nextPage() {
  displayPage(currentPage+1);
}

/*!
 * Affiche la page demandée
 */
void ScoreWidget::displayPage(int pageNumber) {
  currentPage = pageNumber;

  QPixmap image;

  if(pageCount == 1) // dans le cas où il n'y qu'une seul page
    image.load("tmp.png");
  else
    image.load("tmp-page" + QString("%1").arg(currentPage) + ".png");

  imageLabel->setPixmap(image);
  imageLabel->adjustSize();

  pageCountLabel->setText(QString("%1 / %2").arg(currentPage).arg(pageCount));

  if(pageNumber == 1 || pageNumber == -1)
    prevButton->setDisabled(true);
  else
    prevButton->setEnabled(true);

  if(pageNumber == pageCount)
    nextButton->setDisabled(true);
  else
    nextButton->setEnabled(true);

  // quand on change de page, on revient en haut
  scrollArea->horizontalScrollBar()->setValue(0);
  scrollArea->verticalScrollBar()->setValue(0);
}
